package cn.quang.search.admin.service.impl;

import cn.quang.search.admin.entity.dto.Operator;
import cn.quang.search.admin.entity.dto.Result;
import cn.quang.search.admin.entity.po.*;
import cn.quang.search.admin.entity.vo.logictable.ColumnConfigVO;
import cn.quang.search.admin.entity.vo.logictable.LogicTableRequest;
import cn.quang.search.admin.entity.vo.meta.ColumnVO;
import cn.quang.search.admin.mapper.*;
import cn.quang.search.admin.service.IDBMetaService;
import cn.quang.search.admin.service.IEntityLogicTableService;
import cn.quang.search.admin.service.IEntityTableService;
import cn.quang.search.admin.service.ISearchConfigChangeService;
import cn.quang.search.admin.service.common.RedisService;
import cn.quang.search.admin.utils.AssertUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author:  Entity Generator
 * @since:  2024-02-28 10:25:12
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class EntityLogicTableService implements IEntityLogicTableService {
	
	private final EntityLogicTableMapper entityLogicTableMapper;
	private final EntityLogicTableRelationMapper entityLogicTableRelationMapper;
	private final EntityLogicTableFieldDicMapper entityLogicTableFieldDicMapper;
	private final EntityTableMapper entityTableMapper;
	private final EntityDataSourceMapper entityDataSourceMapper;
	private final SearchConditionMapper searchConditionMapper;
	private final SearchResultFetcherMapper searchResultFetcherMapper;
	private final SearchSceneMapper searchSceneMapper;
	private final SearchSceneConfigMapper searchSceneConfigMapper;
	private final SearchConditionTableRelationMapper searchConditionTableRelationMapper;
	private final SearchResultFetcherTableRelationMapper searchResultFetcherTableRelationMapper;
	
	private final IDBMetaService dbMetaService;
	private final IEntityTableService entityTableService;
	private final ISearchConfigChangeService searchConfigChangeService;
	private final RedisService redisService;

	private static final String LOCK_KEY = "CRM3$ENTITY_LOGIC_TABLE$";
	private static final int EXPIRE_SECONDS = 60;

	@Override
	public Result<ColumnConfigVO> columnConfigurations(long logicTableId, long tableId, String cookie){
		Result<ColumnConfigVO> methodResult = new Result<>();
		// 已配置的列
		List<EntityLogicTableFieldDic> fieldDices = entityLogicTableFieldDicMapper.selectByLogicTableId(logicTableId);
		Map<String, EntityLogicTableFieldDic> entityFieldDicMap = fieldDices.stream().collect(Collectors.toMap(EntityLogicTableFieldDic::getDic, v -> v));
		// 全部数据源表
		Result<List<ColumnVO>> columnsResult = dbMetaService.getColumns(tableId, cookie);
		if(columnsResult.isFail()) {
			return methodResult.changeErr("读取数据表下所有的列失败：" + columnsResult.getMessage());
		}
		List<ColumnVO> columns = columnsResult.getTag();
		List<ColumnVO> selectedColumns = Lists.newArrayList();
		List<ColumnVO> notSelectColumns = Lists.newArrayList();
		for (ColumnVO column : columns) {
			if(entityFieldDicMap.containsKey(column.getDic())) {
				EntityLogicTableFieldDic tableFieldDic = entityFieldDicMap.get(column.getDic());
				ColumnVO columnVO = new ColumnVO();
				columnVO.setFieldDicId(tableFieldDic.getFieldDicId());
				columnVO.setDic(tableFieldDic.getDic());
				columnVO.setName(tableFieldDic.getName());
				columnVO.setQueryFieldType(tableFieldDic.getQueryFieldType());
				columnVO.setResultFieldType(tableFieldDic.getResultFieldType());
				columnVO.setResultFieldDefaultValue(tableFieldDic.getResultFieldDefaultValue());
				columnVO.setInTerms(tableFieldDic.getInTerms());
				columnVO.setSupportQuery(tableFieldDic.getSupportQuery());
				columnVO.setSupportSort(tableFieldDic.getSupportSort());
				selectedColumns.add(columnVO);
			} else {
				notSelectColumns.add(column);
			}
		}
		ColumnConfigVO vo = new ColumnConfigVO();
		vo.setSelectedColumns(selectedColumns);
		vo.setNotSelectColumns(notSelectColumns);
		return methodResult.changeSucc(vo);
	}

	/**
	 * 列表查询
	 * @param operator 操作人
	 * @param request 请求
	 */
//	@Override
//	public Result<Pagination<LogicTableListItemVO>> list4View(Operator operator, LogicTableQueryRequest request) {
//		Result<Pagination<LogicTableListItemVO>> Result = new Result<>();
//
//		SearchGroup searchGroup = new SearchGroup(SearchLogicType.AND);
//		if(StringUtils.isNotBlank(request.getName())){
//			searchGroup.addSearch(EntityLogicTable.COL_NAME, SearchOperator.Equal, request.getName());
//		}
//		if(StringUtils.isNotBlank(request.getStartCreateTime())){
//			Date startCreateTime = DateUtil.parse(request.getStartCreateTime(), DateUtil.PATTERN_FULL);
//			searchGroup.addSearch(EntityLogicTable.COL_CREATE_TIME, SearchOperator.GreaterThanOrEqual, startCreateTime);
//		}
//		if(StringUtils.isNotBlank(request.getEndCreateTime())){
//			Date endCreateTime = DateUtil.parse(request.getEndCreateTime(), DateUtil.PATTERN_FULL);
//			searchGroup.addSearch(EntityLogicTable.COL_CREATE_TIME, SearchOperator.LessThan, endCreateTime);
//		}
//		try {
//			Pagination<EntityLogicTable> entitiesPagination = this.entityLogicTableMapper.findEntitiesPagination(null, searchGroup, request.getPageIndex(), request.getPageSize(), String.format("%s desc", EntityDataSource.COL_CREATE_TIME));
//			Pagination<LogicTableListItemVO> pagination = new Pagination<>(request.getPageIndex(), request.getPageSize(), entitiesPagination.getTotalCount());
//			if(CollectionUtils.isNotEmpty(entitiesPagination)) {
//				for (EntityLogicTable entityLogicTable : entitiesPagination) {
//					pagination.add(convertToListItemVo(entityLogicTable));
//				}
//			}
//			return Result.changeSucc(pagination);
//		} catch (Exception e) {
//			logger.error("逻辑表查询失败", e);
//			return Result.changeErr("逻辑表查询失败：" + e.getMessage());
//		}
//	}

	/**
	 * 转换成列表视图
	 */
//	private LogicTableListItemVO convertToListItemVo(EntityLogicTable entityLogicTable) {
//		LogicTableListItemVO vo = new LogicTableListItemVO();
//		vo.setId(entityLogicTable.getId());
//		vo.setName(entityLogicTable.getName());
//		vo.setDescription(entityLogicTable.getDescription());
//		vo.setShardingTable(entityLogicTable.getShardingTable() == DBConstants.DATA_TRUE ? "是" : "否");
//		vo.setShardingTableScfServiceName(entityLogicTable.getShardingTableScfServiceName());
//		vo.setShardingTableScfServiceUrl(entityLogicTable.getShardingTableScfServiceUrl());
//		vo.setDicBelongTableId(entityLogicTable.getDicBelongTableId());
//		try {
//			List<EntityLogicTableRelation> tableRelations = entityLogicTableRelationMapper.selectByLogicTableId(entityLogicTable.getId());
//			if(CollectionUtils.isNotEmpty(tableRelations)){
//				vo.setShardingTableNum(String.valueOf(tableRelations.size()));
//			}else{
//				vo.setShardingTableNum("0");
//			}
//		} catch (Exception e){
//			logger.error(String.format("获取逻辑表(%s)关联的真实表失败", entityLogicTable.getId()), e);
//			vo.setShardingTableNum("N/A");
//		}
//		vo.setCreatorName(BspService.getBspUserNameById(entityLogicTable.getCreatorId()));
//		vo.setCreateTimeFormat(DateUtil.format(entityLogicTable.getCreateTime()));
//		vo.setModifierName(BspService.getBspUserNameById(entityLogicTable.getModifierId()));
//		vo.setModifyTimeFormat(DateUtil.format(entityLogicTable.getModifyTime()));
//		return vo;
//	}

	/**
	 * 详情视图
	 */
//	@Override
//	public Result<LogicTableDetailVO> detail4View(Operator operator, long id) {
//		Result<LogicTableDetailVO> Result = new Result<>();
//		try {
//			EntityLogicTable entity = entityLogicTableMapper.findEntityById(id);
//			return Result.changeSucc(convertToDetailVo(entity));
//		} catch (Exception e) {
//			logger.error(String.format("逻辑表(%s)查询失败", id), e);
//			return Result.changeErr("逻辑表详情查询失败：" + e.getMessage());
//		}
//	}

	/**
	 * 转换成详情
	 */
//	private LogicTableDetailVO convertToDetailVo(EntityLogicTable entity) {
//		LogicTableDetailVO vo = new LogicTableDetailVO();
//		vo.setId(entity.getId());
//		vo.setName(entity.getName());
//		vo.setDescription(entity.getDescription());
//		vo.setShardingTable(entity.getShardingTable() == DBConstants.DATA_TRUE);
//		vo.setShardingTableScfServiceName(entity.getShardingTableScfServiceName());
//		vo.setShardingTableScfServiceUrl(entity.getShardingTableScfServiceUrl());
//		vo.setDicBelongTableId(entity.getDicBelongTableId());
//		// 开始读取关联的真实表
//		try {
//			List<EntityLogicTableRelation> tableRelations = entityLogicTableRelationMapper.selectByLogicTableId(entity.getId());
//			List<TableDataSourceVO> vos = Lists.newArrayList();
//			List<Long> tableIds = tableRelations.stream().map(EntityLogicTableRelation::getTableId).collect(Collectors.toList());
//			List<EntityTable> entityTables = entityTableDao.findEntitiesByIds(tableIds);
//			Map<Long, EntityDataSource> dataSourceCacheMap = Maps.newHashMap();
//			for (EntityTable entityTable : entityTables) {
//				EntityDataSource dataSource = dataSourceCacheMap.computeIfAbsent(entityTable.getDataSourceId(),
//						key -> DecoratorExecutor.execute("获取数据源",
//								() -> entityDataSourceMapper.findEntityById(key),
//								(e) -> { logger.error("获取数据源失败"); return null; }
//						));
//				TableDataSourceVO tableVO = new TableDataSourceVO();
//				tableVO.setTableId(entityTable.getId());
//				tableVO.setTableName(String.format("%s(%s)", entityTable.getTableName(), entityTable.getName()));
//				tableVO.setDataSourceId(entityTable.getDataSourceId());
//				tableVO.setDataSourceName(dataSource == null ? "N/A" : dataSource.getName());
//				vos.add(tableVO);
//			}
//			vo.setTables(vos);
//		} catch (Exception e) {
//			logger.error("逻辑表关联的真实表获取失败", e);
//		}
//		return vo;
//	}

	/**
	 * 添加逻辑表
	 * @param operator 操作人
	 * @param request 请求
	 */
	@Override
	public Result<Long> add(Operator operator, LogicTableRequest request){
		Result<Long> methodResult = new Result<>();

		AssertUtils.argumentBlank(request.getName(), "必须提供逻辑表名称");
		AssertUtils.argumentBlank(request.getDescription(), "必须提供逻辑表描述");
		List<LogicTableRequest.TableNameRequest> tables = request.getTables();
		AssertUtils.argumentCollectionEmpty(tables, "必须提供逻辑表关联的真实表");

		boolean shardingTable = request.isShardingTable();
		if(shardingTable){
			AssertUtils.argumentBlank(request.getShardingTableScfServiceUrl(), "逻辑表依赖分表时，必须提供SCF分表路由解析URL");
			AssertUtils.argumentBlank(request.getShardingTableScfServiceName(), "逻辑表依赖分表时，必须提供SCF分表路由解析服务名");
		}

		Result<?> checkResult = addOrUpdateCheck(request);
		if(checkResult.isFail()) {
			return methodResult.changeErr(checkResult.getMessage());
		}

		String logicTableName = request.getName();

		String uniqueKey = LOCK_KEY + logicTableName;
		String requestId = UUID.randomUUID().toString();
		if(redisService.tryLock(uniqueKey, requestId, EXPIRE_SECONDS)) {
			try {
				EntityLogicTable logicTable = entityLogicTableMapper.selectByName(logicTableName);
				if(logicTable != null) {
					return methodResult.changeErr(String.format("该逻辑表(%s)已经存在！", logicTableName));
				}
				for (LogicTableRequest.TableNameRequest table : tables) {
					EntityTable entityTable = entityTableMapper.selectById(table.getTableId());
					if(entityTable == null) {
						return methodResult.changeErr(String.format("表(%s)在系统内不存在", table.getTableName()));
					}
				}
				List<Long> tableIds = tables.stream().map(LogicTableRequest.TableNameRequest::getTableId).collect(Collectors.toList());
				// 添加逻辑表
				Date now = new Date();
				logicTable = new EntityLogicTable();
				logicTable.setName(request.getName());
				logicTable.setDescription(request.getDescription());
				logicTable.setShardingTable(request.isShardingTable());
				logicTable.setShardingTableScfServiceUrl(request.getShardingTableScfServiceUrl());
				logicTable.setShardingTableScfServiceName(request.getShardingTableScfServiceName());
				logicTable.setCreatorId(operator.getOperatorId());
				logicTable.setCreateTime(now);
				logicTable.setModifierId(operator.getOperatorId());
				logicTable.setModifyTime(now);
				entityLogicTableMapper.insert(logicTable);
				long logicTableId = logicTable.getId();
				// 添加逻辑表和真实表的对应关系
				for (Long tableId : tableIds) {
					EntityLogicTableRelation relation = new EntityLogicTableRelation();
					relation.setLogicTableId(logicTableId);
					relation.setTableId(tableId);
					relation.setCreatorId(operator.getOperatorId());
					relation.setCreateTime(now);
					relation.setModifierId(operator.getOperatorId());
					relation.setModifyTime(now);
					entityLogicTableRelationMapper.insert(relation);
				}
			} catch (Exception e) {
				log.error("添加逻辑表失败", e);
				return methodResult.changeErr("系统异常，请稍后重试");
			} finally {
				redisService.releaseLock(uniqueKey, requestId);
			}
		} else {
			return methodResult.changeErr("操作过于频繁，请稍后重试");
		}
		return methodResult;
	}

	/**
	 * 更新逻辑表
	 * @param operator 操作人
	 * @param request 更新请求
	 */
	@Override
	public Result<?> update(Operator operator, long logicTableId, LogicTableRequest request){
		Result<?> methodResult = new Result<>();

		// 存储增删改的表名称，用于输出日志
		List<String> newTableNames = Lists.newArrayList();
		List<String> modifyTableNames = Lists.newArrayList();
		List<String> deleteTableNames = Lists.newArrayList();

		Result<?> checkResult = addOrUpdateCheck(request);
		if(checkResult.isFail()) {
			return methodResult.changeErr(checkResult.getMessage());
		}

		EntityLogicTable entityLogicTable = entityLogicTableMapper.selectById(logicTableId);
		if(entityLogicTable == null){
			return methodResult.changeErr("不存在该逻辑表！");
		}
		List<LogicTableRequest.TableNameRequest> tables = request.getTables();

		String uniqueKey = LOCK_KEY + (StringUtils.isBlank(request.getName()) ? entityLogicTable.getName() : request.getName());
		String requestId = UUID.randomUUID().toString();
		if(redisService.tryLock(uniqueKey, requestId, EXPIRE_SECONDS)){
			try {
				if(StringUtils.isNotBlank(request.getName()) && !request.getName().equals(entityLogicTable.getName())){
					EntityLogicTable existSameNameLogicTable = entityLogicTableMapper.selectByName(request.getName());
					if(existSameNameLogicTable != null){
						return methodResult.changeErr(String.format("系统内已存在名称为(%s)的逻辑表！", request.getName()));
					}
				}

				Date now = new Date();
				entityLogicTable.setName(request.getName());
				entityLogicTable.setDescription(request.getDescription());
				entityLogicTable.setShardingTable(request.isShardingTable());
				entityLogicTable.setShardingTableScfServiceUrl(request.getShardingTableScfServiceUrl());
				entityLogicTable.setShardingTableScfServiceName(request.getShardingTableScfServiceName());
				entityLogicTable.setModifierId(operator.getOperatorId());
				entityLogicTable.setModifyTime(now);
				entityLogicTableMapper.updateById(entityLogicTable);
				// 更新与真实表的对应关系
				List<EntityLogicTableRelation> relations = entityLogicTableRelationMapper.selectByLogicTableId(logicTableId);
				if(relations == null) { relations = Lists.newArrayList(); }
				Map<Long, EntityLogicTableRelation> tableNameMap = relations.stream().collect(Collectors.toMap(EntityLogicTableRelation::getTableId, v -> v));
				Map<Long, LogicTableRequest.TableNameRequest> tableRequestMap = tables.stream().collect(Collectors.toMap(LogicTableRequest.TableNameRequest::getTableId, v -> v));

				// 比较更新 ： 存在的更新，不存在的新增，未出现在请求中的删除
				for (LogicTableRequest.TableNameRequest tableNameRequest : tables) {
					EntityLogicTableRelation relation = tableNameMap.get(tableNameRequest.getTableId());
					if(relation != null){
						// 已存在的表，执行更新
						relation.setModifierId(operator.getOperatorId());
						relation.setModifyTime(now);
						entityLogicTableRelationMapper.updateById(relation);
						modifyTableNames.add(tableNameRequest.getTableName());
					} else {
						// 新增
						relation = new EntityLogicTableRelation();
						relation.setLogicTableId(logicTableId);
						relation.setTableId(tableNameRequest.getTableId());
						relation.setCreatorId(operator.getOperatorId());
						relation.setCreateTime(now);
						relation.setModifierId(operator.getOperatorId());
						relation.setModifyTime(now);
						entityLogicTableRelationMapper.insert(relation);
						newTableNames.add(tableNameRequest.getTableName());
					}
				}
				// 执行删除
				for (EntityLogicTableRelation tableRelation : relations) {
					if(!tableRequestMap.containsKey(tableRelation.getTableId())){
						EntityTable table = entityTableMapper.selectById(tableRelation.getTableId());
						// 删除
						entityLogicTableRelationMapper.deleteById(tableRelation.getId());
						deleteTableNames.add(table == null ? "未知" : table.getTableName());
					}
				}

				searchConfigChangeService.triggerByLogicTable(logicTableId);
			} catch (Exception e) {
				log.error("更新逻辑表失败", e);
				return methodResult.changeErr("系统异常，请稍后重试");
			} finally {
				redisService.releaseLock(uniqueKey, requestId);
			}
		}

		log.info(String.format("逻辑表关联真实表：新增表%s，修改表%s，删除表%s", newTableNames, modifyTableNames, deleteTableNames));
		return methodResult;
	}

	/**
	 * 新增和更新通用的校验
	 * @param request 请求
	 * @return 校验结果
	 */
	private Result<?> addOrUpdateCheck(LogicTableRequest request){
		Result<?> methodResult = new Result<>();

		List<LogicTableRequest.TableNameRequest> tables = request.getTables();
		if(CollectionUtils.isEmpty(tables)){
			tables = Lists.newArrayList();
		}

		// 校验本次输入的表是否结构相同(仅分表情况下才校验)
		if(request.isShardingTable()) {
			List<Long> tableIds = tables.stream().map(LogicTableRequest.TableNameRequest::getTableId).collect(Collectors.toList());
			Result<?> haveSameTableMetaDataResult = entityTableService.isHaveSameTableMetaData(tableIds);
			if(haveSameTableMetaDataResult.isFail()){
				return methodResult.changeErr("您选择的表存在不同的表结构，请检查：" + haveSameTableMetaDataResult.getMessage());
			}
		}

		return methodResult;
	}

	/**
	 * 删除逻辑表
	 * @param operator 操作人
	 * @param logicTableId 逻辑表ID
	 */
	@Override
	public Result<?> delete(Operator operator, long logicTableId){
		Result<?> methodResult = new Result<>();

		EntityLogicTable logicTable = entityLogicTableMapper.selectById(logicTableId);
		AssertUtils.argumentNull(logicTable, "系统内已不存在该逻辑表！");

		// 检查是否存在配置字典
		List<EntityLogicTableFieldDic> entityLogicTableFieldDices = entityLogicTableFieldDicMapper.selectByLogicTableId(logicTableId);
		AssertUtils.argumentCollectionNotEmpty(entityLogicTableFieldDices, "存在关联的自定义字典：" + entityLogicTableFieldDices.stream().map(input -> String.format("%s(%s)", input.getDic(), input.getName())).collect(Collectors.joining(", ")));

		// 检查是否存在关联场景
		List<SearchSceneConfig> searchSceneConfigs = searchSceneConfigMapper.selectByLogicTableId(logicTableId);
		if(CollectionUtils.isNotEmpty(searchSceneConfigs)){
			List<Long> sceneIds = searchSceneConfigs.stream().map(SearchSceneConfig::getSceneId).collect(Collectors.toList());
			List<SearchScene> scenes = searchSceneMapper.selectList(new QueryWrapper<SearchScene>().lambda().in(SearchScene::getId, sceneIds));
			return methodResult.changeErr("存在关联的场景：" + scenes.stream().map(input -> String.format("%s(%s)", input.getCode(), input.getName())).collect(Collectors.joining(", ")));
		}

		List<SearchConditionTableRelation> conditionRelations = searchConditionTableRelationMapper.selectByLogicTableId(logicTableId);
		if(CollectionUtils.isNotEmpty(conditionRelations)){
			List<Long> conditionIds = conditionRelations.stream().map(SearchConditionTableRelation::getConditionId).collect(Collectors.toList());
			List<SearchCondition> conditions = searchConditionMapper.selectList(new QueryWrapper<SearchCondition>().lambda().in(SearchCondition::getId, conditionIds));
			return methodResult.changeErr("存在关联的查询条件：" + conditions.stream().map(input -> String.format("%s(%s)", input.getDic(), input.getName())).collect(Collectors.joining(", ")));
		}

		List<SearchResultFetcherTableRelation> fetcherRelations = searchResultFetcherTableRelationMapper.selectByLogicTableId(logicTableId);
		if(CollectionUtils.isNotEmpty(fetcherRelations)){
			List<Long> fetcherIds = fetcherRelations.stream().map(SearchResultFetcherTableRelation::getFetcherId).collect(Collectors.toList());
			List<SearchResultFetcher> fetchers = searchResultFetcherMapper.selectList(new QueryWrapper<SearchResultFetcher>().lambda().in(SearchResultFetcher::getId, fetcherIds));
			return methodResult.changeErr("存在关联的取数器：" + fetchers.stream().map(input -> String.format("%s(%s)", input.getDic(), input.getName())).collect(Collectors.joining(", ")));
		}

		// 删除逻辑表关联的真实表
		List<EntityLogicTableRelation> tableRelations = entityLogicTableRelationMapper.selectByLogicTableId(logicTableId);
		if(CollectionUtils.isNotEmpty(tableRelations)) {
			for (EntityLogicTableRelation tableRelation : tableRelations) {
				entityLogicTableRelationMapper.deleteById(tableRelation.getId());
			}
		}

		// 删除该逻辑表关联的自定义字典
		List<EntityLogicTableFieldDic> logicTableFieldDices = entityLogicTableFieldDicMapper.selectByLogicTableId(logicTableId);
		if(CollectionUtils.isNotEmpty(logicTableFieldDices)) {
			for (EntityLogicTableFieldDic logicTableFieldDic : logicTableFieldDices) {
				entityLogicTableFieldDicMapper.deleteById(logicTableFieldDic.getId());
			}
		}

		entityLogicTableMapper.deleteById(logicTableId);

		return methodResult;
	}

}
